package dkdnserver

import (
	"dkdns/dkFramework/configs"
	"dkdns/dkFramework/logger"
	"encoding/json"
	"fmt"
	"net"
	"os"
	"time"

	"github.com/krolaw/dhcp4"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
)

type DHCPConfig struct {
	// ... existing fields ...
	LeaseFile string `json:"lease_file"` // DHCP租约文件路径
}

type DHCPServer struct {
	handler    *DHCPHandler
	config     *configs.Config
	serverIP   net.IP
	options    dhcp4.Options
	started    bool
	leaseTimes map[string]time.Time // MAC地址 -> 租约过期时间
	leaseFile  string               // 租约文件路径
}

type DHCPHandler struct {
	ip            net.IP        // 服务器IP
	leaseDuration time.Duration // 租约时长
	options       dhcp4.Options
	start         net.IP            // 地址池开始
	leaseRange    int               // 可分配地址数量
	leases        map[string]net.IP // MAC地址 -> IP地址
	subnet        net.IPNet         // 子网
	config        *configs.Config
	server        *DHCPServer // 添加对 DHCPServer 的引用
}

// LeaseRecord 租约记录结构
type LeaseRecord struct {
	MAC        string    `json:"mac"`
	IP         string    `json:"ip"`
	ExpireTime time.Time `json:"expire_time"`
}

// NewDHCPServer 创建新的DHCP服务器实例
func NewDHCPServer(config *configs.Config) (*DHCPServer, error) {
	serverIP := net.ParseIP(config.DHCP.ServerIP)
	if serverIP == nil {
		return nil, fmt.Errorf("无效的服务器IP地址")
	}

	_, subnet, err := net.ParseCIDR(config.DHCP.Subnet)
	if err != nil {
		return nil, fmt.Errorf("无效的子网配置: %v", err)
	}

	// 确保所有IP地址都是4字节格式
	options := dhcp4.Options{
		dhcp4.OptionSubnetMask:         subnet.Mask,
		dhcp4.OptionRouter:             net.ParseIP(config.DHCP.Gateway).To4(),
		dhcp4.OptionDomainNameServer:   net.ParseIP(config.DHCP.DNS).To4(),
		dhcp4.OptionIPAddressLeaseTime: dhcp4.OptionsLeaseTime(time.Duration(config.DHCP.LeaseDuration) * time.Hour),
	}

	// 验证起始IP是否在子网范围内
	startIP := net.ParseIP(config.DHCP.StartIP).To4()
	if startIP == nil {
		return nil, fmt.Errorf("无效的起始IP地址")
	}
	if !subnet.Contains(startIP) {
		return nil, fmt.Errorf("起始IP %v 不在子网 %v 范围内", startIP, subnet)
	}

	handler := &DHCPHandler{
		ip:            serverIP.To4(),
		leaseDuration: time.Duration(config.DHCP.LeaseDuration) * time.Hour,
		leases:        make(map[string]net.IP),
		start:         startIP,
		leaseRange:    config.DHCP.LeaseRange,
		subnet:        *subnet,
		options:       options,
		config:        config,
	}

	server := &DHCPServer{
		handler:    handler,
		config:     config,
		serverIP:   serverIP.To4(),
		options:    options,
		leaseTimes: make(map[string]time.Time),
		leaseFile:  config.DHCP.LeaseFile,
	}

	// 设置 handler 对 server 的引用
	handler.server = server

	// 加载已有租约
	if err := server.loadLeasesFromFile(); err != nil {
		logger.Println(fmt.Sprintf("加载租约文件失败: %v", err))
	}

	return server, nil
}

// ServeDHCP 处理DHCP请求
func (h *DHCPHandler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) (d dhcp4.Packet) {
	// 打印更详细的请求信息
	logger.Println(fmt.Sprintf("\n收到DHCP请求:"))
	logger.Println(fmt.Sprintf("- 类型: %v", msgType))
	logger.Println(fmt.Sprintf("- MAC地址: %v", p.CHAddr()))
	logger.Println(fmt.Sprintf("- 当前IP: %v", p.CIAddr()))
	logger.Println(fmt.Sprintf("- 你的IP: %v", p.YIAddr()))
	logger.Println(fmt.Sprintf("- 服务器IP: %v", p.SIAddr()))
	logger.Println(fmt.Sprintf("- 网关IP: %v", p.GIAddr()))
	logger.Println(fmt.Sprintf("- XID: %v", p.XId()))
	logger.Println(fmt.Sprintf("- 标志: %v", p.Flags()))
	logger.Println(fmt.Sprintf("- 选项: %+v", options))

	switch msgType {
	case dhcp4.Discover:
		free, ip := h.getFreeIP(p.CHAddr())
		if !free {
			logger.Println(fmt.Sprintf("无可用IP地址分配给客户端 %s", p.CHAddr()))
			return nil
		}
		logger.Println(fmt.Sprintf("DISCOVER - 为MAC %v 提供IP %v", p.CHAddr(), ip))

		// 记录临时分配
		h.leases[p.CHAddr().String()] = ip

		// 构建完整的选项
		replyOptions := make(dhcp4.Options)

		// 从请求中获取客户端请求的选项列表
		requestedOptions := options[dhcp4.OptionParameterRequestList]
		if len(requestedOptions) > 0 {
			for _, opt := range requestedOptions {
				if val, ok := h.options[dhcp4.OptionCode(opt)]; ok {
					replyOptions[dhcp4.OptionCode(opt)] = val
				}
			}
		}

		// 添加必要的选项
		replyOptions[dhcp4.OptionSubnetMask] = []byte(h.subnet.Mask)
		replyOptions[dhcp4.OptionRouter] = h.ip.To4()
		replyOptions[dhcp4.OptionDomainNameServer] = h.ip.To4()
		replyOptions[dhcp4.OptionServerIdentifier] = h.ip.To4()
		replyOptions[dhcp4.OptionIPAddressLeaseTime] = dhcp4.OptionsLeaseTime(h.leaseDuration)

		// 构建 OFFER 响应
		reply := dhcp4.ReplyPacket(p, dhcp4.Offer, h.ip.To4(), ip.To4(), h.leaseDuration,
			h.options.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))

		logger.Println(fmt.Sprintf("\n发送OFFER响应:"))
		logger.Println(fmt.Sprintf("- 提供IP: %v", ip))
		logger.Println(fmt.Sprintf("- 服务器IP: %v", h.ip))
		logger.Println(fmt.Sprintf("- 租约时间: %v", h.leaseDuration))
		logger.Println(fmt.Sprintf("- 子网掩码: %v", h.subnet.Mask))
		logger.Println(fmt.Sprintf("- 网关: %v", h.ip))
		logger.Println(fmt.Sprintf("- DNS: %v", h.ip))
		logger.Println(fmt.Sprintf("- 选项: %+v", replyOptions))

		return reply

	case dhcp4.Request:
		if server, ok := options[dhcp4.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.ip) {
			logger.Println(fmt.Sprintf("REQUEST - 消息不是发给本服务器的 (目标服务器: %v, 本机: %v)", net.IP(server), h.ip))
			return nil
		}

		reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
		if reqIP == nil {
			reqIP = net.IP(p.CIAddr())
		}

		logger.Println(fmt.Sprintf("\nREQUEST详情:"))
		logger.Println(fmt.Sprintf("- MAC: %v", p.CHAddr()))
		logger.Println(fmt.Sprintf("- 请求IP: %v", reqIP))
		logger.Println(fmt.Sprintf("- 当前IP: %v", p.CIAddr()))

		if len(reqIP) == 0 {
			logger.Println("REQUEST - 无效的请求IP地址")
			return dhcp4.ReplyPacket(p, dhcp4.NAK, h.ip, nil, 0, nil)
		}

		if !h.subnet.Contains(reqIP) {
			logger.Println(fmt.Sprintf("REQUEST - 请求的IP %v 不在子网 %v 范围内", reqIP, h.subnet))
			return dhcp4.ReplyPacket(p, dhcp4.NAK, h.ip, nil, 0, nil)
		}

		// 检查IP是否已被其他客户端使用
		if existingMAC := h.getMACByIP(reqIP); existingMAC != "" && existingMAC != p.CHAddr().String() {
			logger.Println(fmt.Sprintf("REQUEST - IP %v 已被其他客户端 %s 使用", reqIP, existingMAC))
			return dhcp4.ReplyPacket(p, dhcp4.NAK, h.ip, nil, 0, nil)
		}

		// 更新租约
		h.leases[p.CHAddr().String()] = reqIP
		h.updateLeaseTime(p.CHAddr().String())

		logger.Println(fmt.Sprintf("REQUEST - 成功分配IP %v 给客户端 %s", reqIP, p.CHAddr()))

		// 构建 ACK 响应
		reply := dhcp4.ReplyPacket(p, dhcp4.ACK, h.ip, reqIP, h.leaseDuration,
			h.options.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))

		logger.Println(fmt.Sprintf("\n发送ACK响应:"))
		logger.Println(fmt.Sprintf("- 确认IP: %v", reqIP))
		logger.Println(fmt.Sprintf("- 租约时间: %v", h.leaseDuration))
		logger.Println(fmt.Sprintf("- 选项: %+v", h.options))

		return reply

	case dhcp4.Release:
		logger.Println(fmt.Sprintf("RELEASE - 客户端 %s 释放IP地址 %v", p.CHAddr(), h.leases[p.CHAddr().String()]))
		h.releaseIP(p.CHAddr().String())

	case dhcp4.Decline:
		logger.Println(fmt.Sprintf("DECLINE - 客户端 %s 拒绝IP地址 %v", p.CHAddr(), h.leases[p.CHAddr().String()]))
		h.releaseIP(p.CHAddr().String())
	}
	return nil
}

// getMACByIP 根据IP地址查找MAC地址
func (h *DHCPHandler) getMACByIP(ip net.IP) string {
	for mac, leaseIP := range h.leases {
		if leaseIP.Equal(ip) {
			return mac
		}
	}
	return ""
}

// releaseIP 释放IP地址并更新文件
func (h *DHCPHandler) releaseIP(mac string) {
	delete(h.leases, mac)
	delete(h.server.leaseTimes, mac)
	if err := h.server.saveLeasesToFile(); err != nil {
		logger.Println(fmt.Sprintf("保存租约文件失败: %v", err))
	}
}

// updateLeaseTime 更新租约时间并保存到文件
func (h *DHCPHandler) updateLeaseTime(mac string) {
	h.server.leaseTimes[mac] = time.Now().Add(h.leaseDuration)
	if err := h.server.saveLeasesToFile(); err != nil {
		logger.Println(fmt.Sprintf("保存租约文件失败: %v", err))
	}
}

// checkIPConflict 检查IP是否已被使用
func (h *DHCPHandler) checkIPConflict(ip net.IP) bool {
	// 创建 ICMP 连接
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		logger.Println(fmt.Sprintf("创建ICMP连接失败: %v", err))
		return false
	}
	defer c.Close()

	// 构建 ICMP echo 请求
	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID:   os.Getpid() & 0xffff,
			Seq:  1,
			Data: []byte("DHCP_PROBE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		logger.Println(fmt.Sprintf("构建ICMP消息失败: %v", err))
		return false
	}

	// 设置超时
	if err := c.SetDeadline(time.Now().Add(1 * time.Second)); err != nil {
		logger.Println(fmt.Sprintf("设置ICMP超时失败: %v", err))
		return false
	}

	// 发送 ICMP 请求
	if _, err := c.WriteTo(wb, &net.IPAddr{IP: ip}); err != nil {
		logger.Println(fmt.Sprintf("发送ICMP请求失败: %v", err))
		return false
	}

	// 等待响应
	rb := make([]byte, 1500)
	n, _, err := c.ReadFrom(rb)
	if err != nil {
		if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
			// 超时意味着地址可能未被使用
			return false
		}
		logger.Println(fmt.Sprintf("接收ICMP响应失败: %v", err))
		return false
	}

	// 解析响应
	rm, err := icmp.ParseMessage(1, rb[:n])
	if err != nil {
		logger.Println(fmt.Sprintf("解析ICMP响应失败: %v", err))
		return false
	}

	// 如果收到响应，说明IP已被使用
	if rm.Type == ipv4.ICMPTypeEchoReply {
		logger.Println(fmt.Sprintf("检测到IP冲突: %v 已被使用", ip))
		return true
	}

	return false
}

// getFreeIP 获取可用的IP地址
func (h *DHCPHandler) getFreeIP(mac net.HardwareAddr) (bool, net.IP) {
	// 首先检查是否已有分配的IP
	if ip, exists := h.leases[mac.String()]; exists {
		if leaseTime, exists := h.server.leaseTimes[mac.String()]; exists && time.Now().Before(leaseTime) {
			logger.Println(fmt.Sprintf("为MAC %v 续租IP %v", mac, ip))
			return true, ip
		}
	}

	startIP := h.start
	logger.Println(fmt.Sprintf("地址池起始IP: %v", startIP))
	logger.Println(fmt.Sprintf("地址池范围: %d", h.leaseRange))

	// 分配新IP
	for i := 1; i < h.leaseRange; i++ {
		ip := make(net.IP, len(startIP))
		copy(ip, startIP)
		ip[3] += byte(i)

		if !h.subnet.Contains(ip) {
			logger.Println(fmt.Sprintf("IP %v 不在子网 %v 范围内，跳过", ip, h.subnet))
			continue
		}

		// 检查IP是否已被分配
		if h.isIPLeased(ip) {
			continue
		}

		// 检查IP是否已被其他设备使用
		if h.checkIPConflict(ip) {
			logger.Println(fmt.Sprintf("IP %v 已被其他设备使用，跳过", ip))
			continue
		}

		logger.Println(fmt.Sprintf("为MAC %v 分配新IP %v", mac, ip))
		return true, ip
	}

	logger.Println(fmt.Sprintf("无法为MAC %v 分配IP，地址池已满", mac))
	return false, nil
}

// isIPLeased 检查IP是否已被分配
func (h *DHCPHandler) isIPLeased(ip net.IP) bool {
	// 检查IP是否已被分配且租约未过期
	for mac, leaseIP := range h.leases {
		if leaseIP.Equal(ip) {
			if leaseTime, exists := h.server.leaseTimes[mac]; exists {
				return time.Now().Before(leaseTime)
			}
			return true
		}
	}
	return false
}

// RunDHCPServer 启动DHCP服务器
func RunDHCPServer(config *configs.Config) error {
	server, err := NewDHCPServer(config)
	if err != nil {
		return fmt.Errorf("创建DHCP服务器失败: %v", err)
	}

	// 获取所有网络接口
	interfaces, err := net.Interfaces()
	if err != nil {
		logger.Println(fmt.Sprintf("获取网络接口列表失败: %v", err))
	} else {
		logger.Println("可用网络接口列表:")
		for _, iface := range interfaces {
			addrs, _ := iface.Addrs()
			logger.Println(fmt.Sprintf("- 接口: %s (Index: %d, MTU: %d, Flags: %v)",
				iface.Name, iface.Index, iface.MTU, iface.Flags))
			logger.Println(fmt.Sprintf("  MAC: %v", iface.HardwareAddr))
			logger.Println(fmt.Sprintf("  地址: %v", addrs))
		}
	}

	logger.Println(fmt.Sprintf("\nDHCP服务器配置:"))
	logger.Println(fmt.Sprintf("- 服务器IP: %s", server.serverIP))
	logger.Println(fmt.Sprintf("- 监听接口: %s", config.DHCP.Interface))
	logger.Println(fmt.Sprintf("- 端口: %d", config.DHCP.Port))
	logger.Println(fmt.Sprintf("- 地址池: %s (范围: %d)", server.handler.start, server.handler.leaseRange))
	logger.Println(fmt.Sprintf("- 子网: %s", server.handler.subnet))
	logger.Println(fmt.Sprintf("- 网关: %s", config.DHCP.Gateway))
	logger.Println(fmt.Sprintf("- DNS: %s", config.DHCP.DNS))
	logger.Println(fmt.Sprintf("- 租约时长: %d小时", config.DHCP.LeaseDuration))

	// 检查指定的接口是否存在
	iface, err := net.InterfaceByName(config.DHCP.Interface)
	if err != nil {
		logger.Println(fmt.Sprintf("!!! 错误: 找不到指定的网络接口 %s: %v", config.DHCP.Interface, err))
		return fmt.Errorf("找不到指定的网络接口: %v", err)
	}

	logger.Println(fmt.Sprintf("\n准备在接口 %s 上启动DHCP服务", iface.Name))
	logger.Println(fmt.Sprintf("接口详情:"))
	logger.Println(fmt.Sprintf("- MAC地址: %v", iface.HardwareAddr))
	logger.Println(fmt.Sprintf("- MTU: %d", iface.MTU))
	logger.Println(fmt.Sprintf("- 标志: %v", iface.Flags))

	addrs, err := iface.Addrs()
	if err == nil {
		logger.Println(fmt.Sprintf("- IP地址:"))
		for _, addr := range addrs {
			logger.Println(fmt.Sprintf("  %v", addr))
		}
	}

	logger.Println("\n正在启动DHCP服务...")
	err = dhcp4.ListenAndServeIf(config.DHCP.Interface, server.handler)
	if err != nil {
		logger.Println(fmt.Sprintf("!!! DHCP服务器启动失败: %v", err))
		return fmt.Errorf("DHCP服务器启动失败: %v", err)
	}

	// 启动租约清理协程
	go server.cleanupLeases()

	return nil
}

// cleanupLeases 清理过期的租约
func (s *DHCPServer) cleanupLeases() {
	ticker := time.NewTicker(1 * time.Hour)
	defer ticker.Stop()

	for range ticker.C {
		now := time.Now()
		logger.Println("开始清理过期租约...")
		for mac, expireTime := range s.leaseTimes {
			if now.After(expireTime) {
				ip := s.handler.leases[mac]
				delete(s.handler.leases, mac)
				delete(s.leaseTimes, mac)
				logger.Println(fmt.Sprintf("清理过期租约: MAC %s, IP %v", mac, ip))
			}
		}
		// 保存更新后的租约信息
		if err := s.saveLeasesToFile(); err != nil {
			logger.Println(fmt.Sprintf("保存租约文件失败: %v", err))
		}
		logger.Println(fmt.Sprintf("当前活动租约数量: %d", len(s.leaseTimes)))
	}
}

// saveLeasesToFile 保存租约信息到文件
func (s *DHCPServer) saveLeasesToFile() error {
	records := make([]LeaseRecord, 0)
	for mac, expireTime := range s.leaseTimes {
		if ip, ok := s.handler.leases[mac]; ok {
			records = append(records, LeaseRecord{
				MAC:        mac,
				IP:         ip.String(),
				ExpireTime: expireTime,
			})
		}
	}

	data, err := json.MarshalIndent(records, "", "  ")
	if err != nil {
		return fmt.Errorf("序列化租约数据失败: %v", err)
	}

	err = os.WriteFile(s.leaseFile, data, 0644)
	if err != nil {
		return fmt.Errorf("写入租约文件失败: %v", err)
	}

	logger.Println(fmt.Sprintf("已保存 %d 条租约记录到文件: %s", len(records), s.leaseFile))
	return nil
}

// loadLeasesFromFile 从文件加载租约信息
func (s *DHCPServer) loadLeasesFromFile() error {
	data, err := os.ReadFile(s.leaseFile)
	if err != nil {
		if os.IsNotExist(err) {
			logger.Println("租约文件不存在，将创建新文件")
			return nil
		}
		return fmt.Errorf("读取租约文件失败: %v", err)
	}

	var records []LeaseRecord
	if err := json.Unmarshal(data, &records); err != nil {
		return fmt.Errorf("解析租约文件失败: %v", err)
	}

	now := time.Now()
	validCount := 0
	for _, record := range records {
		// 只加载未过期的租约
		if record.ExpireTime.After(now) {
			s.leaseTimes[record.MAC] = record.ExpireTime
			s.handler.leases[record.MAC] = net.ParseIP(record.IP)
			validCount++
		}
	}

	logger.Println(fmt.Sprintf("从文件加载了 %d 条有效租约记录", validCount))
	return nil
}
